/**   
 * @Title: HttpsUtil.java 
 * @Package org.apache.http.utils 
 * @Description: TODO(用一句话描述该文件做什么) 
 * @author peter  
 * @date 2016年4月18日 下午4:13:32 
 * @version V1.0   
 */
package com.lsh.oms.core.utils.http;

import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

/** 
 * @ClassName: HttpsTemplate
 * @Description: https请求处理工具类
 * @author peter
 * @date 2017年1月5日
 */
public class HttpsTemplate {
	
	private static SSLConnectionSocketFactory socketFactory;
	private static RequestConfig requestConfig;
	private static final int MAX_TIMEOUT = 20000;

	static {

		RequestConfig.Builder configBuilder = RequestConfig.custom();
		// 设置连接超时
		configBuilder.setConnectTimeout(MAX_TIMEOUT);
		// 设置读取超时
		configBuilder.setSocketTimeout(MAX_TIMEOUT);
		// 设置从连接池获取连接实例的超时
		configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
		// 在提交请求之前 测试连接是否可用
		requestConfig = configBuilder.build();
	}
	
	
	/**
	 * @Title: doHttpsGet 
	 * @Description: TODO(发送 SSL GET 请求（HTTPS）) 
	 * @param @param url
	 * @param @return
	 * @return CloseableHttpResponse
	 * @throws
	 */
	public static String doGetSSL(String url) {
	
		return doGetSSL(url, new HashMap<String,Object>());
	}
	
	
	/**
	 * 发送 GET 请求（HTTP），K-V形式
	 * 
	 * @param url
	 * @param params
	 * @return
	 */
	public static String doGetSSL(String url, Map<String, Object> params) {
		String apiUrl = url;
		StringBuffer param = new StringBuffer();
		int i = 0;
		for (String key : params.keySet()) {
			if (i == 0)
				param.append("?");
			else
				param.append("&");
			param.append(key).append("=").append(params.get(key));
			i++;
		}
		apiUrl += param;
		String result = null;
		HttpClient httpclient = createHttpsClient();
		try {
			HttpGet httpPost = new HttpGet(apiUrl);
			HttpResponse response = httpclient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();

			System.out.println("执行状态码 : " + statusCode);

			HttpEntity entity = response.getEntity();
			if (entity != null) {
				result = EntityUtils.toString(entity);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 发送 POST 请求（HTTP），不带输入数据
	 * 
	 * @param apiUrl
	 * @return
	 */
	public static String doPostSSL(String apiUrl) {
		return doPostSSL(apiUrl, new HashMap<String, String>(),new HashMap<String, String>());
	}

	/**
	 * @Title: doPostSSL 
	 * @Description: TODO(发送 SSL POST 请求（HTTPS），K-V形式) 
	 * @param @param apiUrl
	 * @param @param params
	 * @param @return
	 * @return String
	 * @throws
	 */
	public static String doPostSSL(String apiUrl, Map<String, String> params,Map<String, String> headMap) {
		CloseableHttpClient httpClient = createHttpsClient();
		HttpPost httpPost = new HttpPost(apiUrl);
		CloseableHttpResponse response = null;
		String httpStr = null;

		try {
			httpPost.setConfig(requestConfig);
			if(headMap != null && !headMap.isEmpty()) {
				Iterator start = headMap.entrySet().iterator();
				while (start.hasNext()) {
					Map.Entry<String,String> entry = (Map.Entry) start.next();
					httpPost.addHeader(entry.getKey(), entry.getValue());
				}
			}
			List<NameValuePair> pairList = new ArrayList<>(params.size());
			for (Map.Entry<String, String> entry : params.entrySet()) {
				NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue());
				pairList.add(pair);
			}
			httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8")));
			response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				return null;
			}
			HttpEntity entity = response.getEntity();
			if (entity == null) {
				return null;
			}
			httpStr = EntityUtils.toString(entity, "utf-8");

//			System.out.println("httpStr is " + httpStr);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return httpStr;
	}

	/**
	 * @Title: doPostSSL 
	 * @Description: TODO(发送 SSL POST 请求（HTTPS），JSON形式) 
	 * @param @param apiUrl
	 * @param @param json
	 * @param @return
	 * @return String
	 * @throws
	 */
	public static String doPostSSL(String apiUrl, String json) {
		CloseableHttpClient httpClient = createHttpsClient();
		HttpPost httpPost = new HttpPost(apiUrl);
		CloseableHttpResponse response = null;
		String httpStr = null;

		ResponseHandler<String> rh = new ResponseHandler<String>() {

			@Override
			public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
				StatusLine statusLine = response.getStatusLine();
				HttpEntity entity = response.getEntity();
				if (statusLine.getStatusCode() >= 300) {
					throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
				}
				if (entity == null) {
					throw new ClientProtocolException("Response contains no content");
				}

				return EntityUtils.toString(entity);
			}
		};

		try {
			httpPost.setConfig(requestConfig);
			StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");// 解决中文乱码问题
			stringEntity.setContentEncoding("UTF-8");
			stringEntity.setContentType("application/json");
			httpPost.setEntity(stringEntity);
			httpStr = httpClient.execute(httpPost, rh);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
					httpClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return httpStr;
	}

	/*
	 * 忽略SSL认证
	 */
	private static TrustManager truseAllManager = new X509TrustManager() {

		@Override
		public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

		}

		@Override
		public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return new X509Certificate[] {};
		}

	};


	/*
	 * @Title: enableSSL 
	 * @Description: TODO(初始化 socketFactory) 
	 * @param 
	 * @return void
	 * @throws
	 */
	private static void enableSSL() {
		// 调用ssl
		try {
			// SSLContext sslcontext = SSLContext.getInstance("TLS");
			SSLContext sslcontext = SSLContexts.custom().build();
			sslcontext.init(null, new TrustManager[] { truseAllManager }, new SecureRandom());
			socketFactory = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE);

		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	/**
	 * @Title: createHttpsClient
	 * @Description: TODO(创建httpsclient) 
	 * @param @return
	 * @return CloseableHttpClient
	 * @throws
	 */
	public static CloseableHttpClient createHttpsClient() {
		if (socketFactory == null) {
			enableSSL();
		}
		// 配置config
		RequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).setExpectContinueEnabled(true)
				.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)).setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();

		// 设置连接池
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", PlainConnectionSocketFactory.INSTANCE).register("https", socketFactory)
				.build();
		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);

		connectionManager.setMaxTotal(100);
		connectionManager.setDefaultMaxPerRoute(10);

		return HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(config).build();
	}

}
